home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / tsr / xsnap.zip / XSNAP.C < prev    next >
C/C++ Source or Header  |  1992-11-09  |  33KB  |  1,216 lines

  1. /*
  2.  *   xsnap -- take a snapshot of a portion of the screen.
  3.  *
  4.  *   Copyright 1989 Clauss Strauch
  5.  *                  cbs@cad.cs.cmu.edu
  6.  *
  7.  *   Permission to use, copy, modify, and distribute this software and its
  8.  *   documentation for any purpose and without fee is hereby granted.
  9.  *   This software is provided "as is", without express or implied warranty.
  10.  *   
  11.  *   Modified by Bill Janssen janssen@parc.xerox.com 
  12.  *    add -xwd, -atk and -region options
  13.  *   Modified by Arnaud Le Hors lehors@mirsa.inria.fr  November 14 1990
  14.  *    fix code about region option
  15.  *    add -xpm option
  16.  *
  17.  */
  18.  
  19. #include <stdio.h> 
  20. #include <X11/Xlib.h>
  21. #include <X11/Xos.h>
  22. #include <X11/Xutil.h>
  23. #include <X11/cursorfo.h>
  24.  
  25. #ifndef TRUE
  26. #define TRUE 1
  27. #endif
  28.  
  29. #ifndef FALSE
  30. #define FALSE 0
  31. #endif
  32.  
  33. /*  Leave arguments as globals, since there are so many of them.
  34.  *  They'll only be referenced in process_args and main.
  35.  */
  36.  
  37. char *display_string = NULL;         /* display we'll open */
  38. int  border_width = 2;               /* border_width  of the snapshot window */
  39. int  start_iconic = FALSE;           /* start snap window in iconic state?  */
  40. char *color_name = NULL;             /* user-supplied name of border color */
  41. char *window_geom_string = NULL;     /* geometry of snapshot window */
  42. char *icon_geom_string = NULL;       /* icon geometry */
  43. char *region_geom_string = NULL;     /* location of region to copy */
  44. char *app_name = "xsnap";            /* name of application for window manager */
  45. int  xwd_output = FALSE;             /* store in xwd format */
  46. int  atk_output = FALSE;             /* store in ATK format */
  47. int  xpm_output = FALSE;             /* store in XPM format */
  48. char *output_file_name = NULL;       /* file to store in */
  49. int  cut_buffer = FALSE;             /* store in cutbuffer in ATK format? */
  50. int  grab_server = TRUE;             /* grab the server? */
  51. int  display_in_window = TRUE;       /* display in window after snap? */
  52.  
  53. /*
  54.  *  create_event_window returns the ID of a InputOnly window that covers
  55.  *  the given window.
  56.  */
  57.  
  58. Window create_event_window(a_display,a_window, init_cursor)
  59. Display *a_display;
  60. Window a_window;
  61. {
  62.     XSetWindowAttributes xswa;
  63.     unsigned long xswa_valuemask;
  64.     Window root_win;
  65.     Window event_window;
  66.     unsigned int win_width, win_height;
  67.     unsigned int  win_border_width, win_depth;
  68.     int win_x, win_y;
  69.  
  70.     /* get the geometry of the window  */
  71.  
  72.     XGetGeometry(a_display, a_window, &root_win, &win_x, &win_y,
  73.         &win_width, &win_height, &win_border_width, &win_depth);
  74.  
  75.     /* make an input only window to get events from  */
  76.  
  77.     xswa.cursor = init_cursor;
  78.     xswa.override_redirect = True;
  79.     xswa.event_mask = ButtonPressMask | ButtonReleaseMask | Button1MotionMask;
  80.     xswa_valuemask = CWCursor | CWOverrideRedirect | CWEventMask;
  81.     event_window = XCreateWindow(a_display, a_window, win_x, win_y, win_width,
  82.         win_height, 0, 0, InputOnly, CopyFromParent, 
  83.         xswa_valuemask, &xswa);
  84.     return(event_window);
  85. }
  86.  
  87. /*
  88.  *   draw box draws a box on the given window, with the given GC 
  89.  *
  90.  */
  91.  
  92. void draw_box(a_display, a_window, a_gc, x1, y1, x2, y2)
  93. GC a_gc;
  94. Window a_window;
  95. Display *a_display;
  96. int x1, y1, x2, y2;
  97. {
  98.     XSegment segments[4];
  99.     segments[0].x1 = (short)x1;
  100.     segments[0].y1 = (short)y1;
  101.     segments[0].x2 = (short)x1;
  102.     segments[0].y2 = (short)y2;
  103.  
  104.     segments[1].x1 = (short)x1;
  105.     segments[1].y1 = (short)y1;
  106.     segments[1].x2 = (short)x2;
  107.     segments[1].y2 = (short)y1;
  108.  
  109.     segments[2].x1 = (short)x2;
  110.     segments[2].y1 = (short)y2;
  111.     segments[2].x2 = (short)x1;
  112.     segments[2].y2 = (short)y2;
  113.  
  114.     segments[3].x1 = (short)x2;
  115.     segments[3].y1 = (short)y2;
  116.     segments[3].x2 = (short)x2;
  117.     segments[3].y2 = (short)y1;
  118.  
  119.     XDrawSegments(a_display, a_window, a_gc, segments, 4);
  120. }
  121.  
  122. /*
  123.  *  get_region
  124.  * takes as input:
  125.  *    display
  126.  *    window to get region from 
  127.  *    pointers to x1, y1, width, height
  128.  *  
  129.  *   returns:  the position and width and height of a
  130.  *             user selected region via the given pointers.
  131.  *
  132.  */
  133.  
  134.  
  135. get_region(a_display, a_window,  x, y, width, height)
  136. Display *a_display;
  137. Window a_window;
  138. int *x, *y;
  139. unsigned int *height, *width;
  140.  
  141. {
  142.     Window event_window;
  143.     Cursor up_right_curs, up_left_curs;
  144.     Cursor low_right_curs, low_left_curs;
  145.     Cursor current_cursor;
  146.     int done;
  147.     int init_x, init_y;
  148.     int last_x, last_y;
  149.     XEvent event;
  150.     GC xor_gc;
  151.     XGCValues xor_gc_values;             /* for creating xor_gc */
  152.     unsigned long xor_gc_valuemask;       /* valuemask for creating xor_gc */
  153.  
  154.     /* make the GC and cursors we'll need */
  155.  
  156.     up_right_curs = XCreateFontCursor(a_display, XC_ur_angle);
  157.  
  158.     up_left_curs = XCreateFontCursor(a_display, XC_ul_angle);
  159.  
  160.     low_right_curs = XCreateFontCursor(a_display, XC_lr_angle);
  161.     
  162.     low_left_curs = XCreateFontCursor(a_display, XC_ll_angle);
  163.     
  164.  
  165.  
  166.     xor_gc_valuemask = GCFunction | GCSubwindowMode  | GCForeground;
  167.     xor_gc_values.function = GXxor;
  168.     xor_gc_values.foreground = 0xfd;
  169.     xor_gc_values.subwindow_mode = IncludeInferiors;
  170.     xor_gc = XCreateGC(a_display, a_window, xor_gc_valuemask, &xor_gc_values);
  171.  
  172.     event_window = create_event_window(a_display, a_window,up_left_curs);
  173.     XMapRaised(a_display, event_window);
  174.  
  175.  
  176.     if (XGrabPointer(a_display, event_window, True, 
  177.         ButtonPressMask,
  178.         GrabModeAsync, GrabModeAsync, None, up_left_curs, 
  179.              CurrentTime) != 0)
  180.       {
  181.         fprintf(stderr, "Cannot grab pointer.");
  182.         exit(1);
  183.       }
  184.  
  185.  
  186.     /* get the initial button  press */
  187.     done = FALSE;
  188.     while (! done)
  189.     {
  190.         XNextEvent(a_display, &event);
  191.         switch(event.type)
  192.         {
  193.         case MappingNotify:
  194.             XRefreshKeyboardMapping(&event);
  195.             break;
  196.         case ButtonPress:
  197.             if (event.xbutton.button == 1)
  198.             {
  199.                 init_x = event.xbutton.x;
  200.                 init_y = event.xbutton.y;
  201.  
  202.  
  203.                 done = TRUE;
  204.                 break;
  205.             }
  206.         }
  207.     }
  208.  
  209.  
  210.     /*  now we have the location of one corner of the box.   change the cursor,
  211.  *  and have the user drag out the area.
  212.  */
  213.     current_cursor = low_right_curs;
  214.     last_x = init_x;
  215.     last_y = init_y;
  216.     XChangeActivePointerGrab(a_display, ButtonReleaseMask | Button1MotionMask,
  217.         current_cursor, CurrentTime);
  218.     done = FALSE;
  219.     draw_box(a_display, a_window, xor_gc, init_x, init_y, last_x, last_y);
  220.     while (! done)
  221.     {
  222.         XNextEvent(a_display, &event);
  223.         switch(event.type)
  224.         {
  225.         case MappingNotify:
  226.             XRefreshKeyboardMapping(&event);
  227.             break;
  228.         case MotionNotify:
  229.             draw_box(a_display, a_window, xor_gc, 
  230.                 init_x, init_y, last_x, last_y);  /* erase old */
  231.             last_x = event.xmotion.x;
  232.             last_y = event.xmotion.y;
  233.             draw_box(a_display, a_window, xor_gc, 
  234.                 init_x, init_y, last_x, last_y); /* draw new  */
  235.             /*  Change cursor to correspond to position of pointer */
  236.             if ((init_x < last_x) && (init_y < last_y)
  237.                 && (current_cursor != low_right_curs))
  238.             {
  239.                 current_cursor = low_right_curs;
  240.                 XChangeActivePointerGrab(a_display, 
  241.                     ButtonReleaseMask | Button1MotionMask,
  242.                     low_right_curs, CurrentTime);
  243.             }
  244.             else if ((last_x < init_x) && (last_y < init_y)
  245.                 &&  (current_cursor != up_left_curs))
  246.             {
  247.                 current_cursor = up_left_curs;
  248.                 XChangeActivePointerGrab(a_display, 
  249.                     ButtonReleaseMask | Button1MotionMask,
  250.                     up_left_curs, CurrentTime);
  251.             }
  252.  
  253.             else if ((init_x < last_x) && (last_y < init_y)
  254.                 && (current_cursor != up_right_curs))
  255.             {
  256.                 current_cursor = up_right_curs;
  257.                 XChangeActivePointerGrab(a_display, 
  258.                     ButtonReleaseMask | Button1MotionMask,
  259.                     up_right_curs, CurrentTime);
  260.  
  261.             }
  262.             else if ((last_x < init_x) && (init_y < last_y)
  263.                 && (current_cursor != low_left_curs))
  264.             {
  265.                 current_cursor = low_left_curs;
  266.                 XChangeActivePointerGrab(a_display, 
  267.                     ButtonReleaseMask | Button1MotionMask,
  268.                     low_left_curs, CurrentTime);
  269.             }
  270.  
  271.             break;
  272.         case ButtonRelease:
  273.             if (event.xbutton.button == 1)
  274.             {
  275.                 done = TRUE;
  276.                 draw_box(a_display, a_window, xor_gc, 
  277.                     init_x, init_y, last_x, last_y);  /* erase last box drawn */
  278.             }
  279.             break;
  280.         }
  281.     }
  282.     XFlush(a_display);   /*  gets rid of last box on screen  */
  283.     if (init_x < last_x) *x = init_x;
  284.     else *x = last_x;
  285.     if (init_y < last_y) *y = init_y;
  286.     else *y = last_y;
  287.     *width = (unsigned int)abs(last_x - init_x);
  288.     *height = (unsigned int)abs(last_y - init_y);
  289.     /* clean up after ourself: */
  290.  
  291.     XDestroyWindow(a_display, event_window);
  292.     XFreeGC(a_display, xor_gc);
  293.  
  294.     /* we'll let the caller ungrab the pointer */
  295.  
  296. }
  297.  
  298. /* 
  299.  *  get_pixmap_region 
  300.  *
  301.  *       input :
  302.  *               a display, a window, x, y, width, height, interactive.
  303.  *               if interactive, the user is prompted for a region,
  304.  *               other wise the given region is copied to a pixmap.
  305.  *       returns : a pixmap containing a copy of a user-specified area
  306.  *                 of the given window;
  307.  *
  308.  */
  309.  
  310. Pixmap get_pixmap_region(a_display, a_screen, a_window, a_gc,  x, y, 
  311. width, height, depth, interactive)
  312. Display *a_display;
  313. GC a_gc;
  314. int a_screen;
  315. Window a_window;
  316. int *x, *y;
  317. unsigned int *width, *height, *depth;
  318. int interactive;
  319.  
  320. {
  321.     int reg_x, reg_y;
  322.     unsigned int reg_width, reg_height;
  323.     Pixmap pixmap_returned;
  324.     int return_flag;
  325.     int junk_root, junk_left, junk_top, junk_width, junk_height, junk_border_width;
  326.  
  327.     if (interactive){
  328.         get_region(a_display, a_window, ®_x, ®_y,
  329.             ®_width, ®_height);
  330.         *x = reg_x;
  331.         *y = reg_y;
  332.         *width = reg_width;
  333.         *height = reg_height;
  334.     }
  335.  
  336.     /* Use the depth of `a_window' for the depth of the pixmap */
  337.       
  338.     XGetGeometry (a_display, a_window, &junk_root, &junk_left, &junk_top,
  339.               &junk_width, &junk_height, &junk_border_width, depth);
  340.  
  341.     pixmap_returned = XCreatePixmap(a_display, 
  342.                     DefaultRootWindow(a_display),
  343.                     *width, *height, *depth);
  344.  
  345.     /*  now copy the area we specified  */
  346.  
  347.     XCopyArea(a_display, a_window, pixmap_returned, a_gc, *x, *y, 
  348.           *width, *height, 0, 0);
  349.     if (interactive)  XUngrabPointer(a_display, CurrentTime);
  350.     return(pixmap_returned);
  351. }
  352.  
  353.  
  354. /* 
  355.  *  X error handler for,  mainly for future use
  356.  */
  357.  
  358. int my_X_error_handler(display, myerr)
  359. Display *display;
  360. XErrorEvent *myerr;
  361. {
  362.   char msg[80];  
  363.  
  364. /* if we get a BadAlloc error, it's probably 'cuz we couldn't allocate
  365.  * the pixmap.  Tell the user this.
  366.  */
  367.   fprintf(stderr,"xsnap:\n"); 
  368.   if ((myerr->error_code) == BadAlloc)   
  369.     {
  370.       fprintf(stderr, "Insufficient resources for operation.\n");
  371.       fprintf(stderr, "Probably not enough memory to allocate pixmap.\n");
  372.     }
  373.  
  374. /* Now print out the error string that X generates */
  375.   
  376.   XGetErrorText(display, myerr->error_code, msg,80);
  377.   fprintf(stderr, "Error code %s\n", msg);
  378. /* no way to continue, so we'll just bag it  */
  379.   exit(1);
  380. }
  381.   
  382.  
  383. /*
  384.  *  print a usage message to the user
  385.  */
  386.  
  387. usage()
  388. {
  389.     printf("%s\n", "Usage:  xsnap [-options...]");
  390.     printf("%s\n", "Where options are:");
  391.     printf("%s\n", "[-display host:display]  Display to connect to.");
  392.     printf("%s\n", "[-bd borderwidth]        Color of border");
  393.     printf("%s\n", "[-bw borderwidth]        Width of border");
  394.     printf("%s\n", "[-geometry geom]         Geometry of snapshot window");
  395.     printf("%s\n", "[-icongeometry geom]     Location of icon.");
  396.     printf("%s\n", "[-region geom]           Region of screen to be copied.");
  397.     printf("%s\n", "[-iconic]                Start up in iconic state");
  398.     printf("%s\n", "[-name name]             Passed to window manager for name of window.");
  399.     printf("%s\n", "[-nograb]                Don't grab server during specification of region.");
  400.     printf("%s\n", "[-xwd]                   Write to output in `xwd' format.");
  401.     printf("%s\n", "[-atk]                   Write to output in `atk' format.");
  402.     printf("%s\n", "[-xpm]                   Write to output in `xpm' format.");
  403.     printf("%s\n", "[-file filename]         Write output to file `filename'.");
  404.     printf("%s\n", "[-cutbuffer]             Store in cutbuffer in Andrew raster format.");
  405.     printf("%s\n", "[-noshow]                Don't display in window.");
  406.     exit(1);
  407. }
  408.  
  409. /*
  410.  *        get the arguments.   arguments are matched to the first
  411.  *        distinguishing substring.
  412.  */
  413. process_args(argc, argv)
  414. int argc;
  415. char **argv;
  416. {
  417.     int i;
  418.  
  419.     for (i = 1; i < argc; i++)
  420.     {
  421.         if (strncmp(argv[i], "-h", 2) == 0)
  422.         {
  423.             usage();
  424.             continue;
  425.         }
  426.         if (strncmp(argv[i], "-display", 2) == 0)
  427.         {
  428.             display_string = argv[++i];
  429.             continue;
  430.         }
  431.         if (strncmp(argv[i], "-bw", 3) == 0)
  432.         {
  433.             border_width = atoi(argv[++i]);
  434.             continue;
  435.         }
  436.         if (strncmp(argv[i], "-bd", 3) == 0)
  437.         {
  438.             color_name = argv[++i];
  439.             continue;
  440.         }
  441.         if (strncmp(argv[i], "-ge", 3) == 0)
  442.         {
  443.             window_geom_string = argv[++i];
  444.             continue;
  445.         }
  446.         if (strncmp(argv[i], "-icong", 6) == 0)
  447.         {
  448.             icon_geom_string = argv[++i];
  449.             continue;
  450.         }
  451.         if (strncmp(argv[i], "-r", 2) == 0)
  452.         {
  453.             region_geom_string = argv[++i];
  454.             continue;
  455.         }
  456.         if (strncmp(argv[i], "-iconi", 6) == 0)
  457.         {
  458.             start_iconic = TRUE;
  459.             continue;
  460.         }
  461.         if (strncmp(argv[i], "-na", 3) == 0)
  462.         {
  463.             app_name = argv[++i];
  464.             continue;
  465.         }
  466.         if (strncmp(argv[i], "-nog", 4) == 0)
  467.         {
  468.             grab_server = FALSE;
  469.             continue;
  470.         }
  471.         if (strncmp(argv[i], "-nos", 4) == 0)
  472.         {
  473.           display_in_window = FALSE;
  474.           continue;
  475.         }
  476.         if (strncmp(argv[i], "-xwd", 4) == 0)
  477.         {
  478.           xwd_output = TRUE;
  479.           continue;
  480.         }
  481.         if (strncmp(argv[i], "-atk", 4) == 0)
  482.         {
  483.           atk_output = TRUE;
  484.           continue;
  485.         }
  486.         if (strncmp(argv[i], "-xpm", 4) == 0)
  487.         {
  488.           xpm_output = TRUE;
  489.           continue;
  490.         }
  491.         if (strncmp(argv[i], "-file", 5) == 0)
  492.         {
  493.           output_file_name = argv[++i];
  494.           continue;
  495.         }
  496.         if (strncmp(argv[i], "-cutb", 5) == 0)
  497.         {
  498.           cut_buffer = TRUE;
  499.           continue;
  500.         }
  501.         usage();
  502.     }
  503. }
  504.  
  505. /*
  506.  * Get the XColors of all pixels in image - returns # of colors
  507.  */
  508. int Get_XColors(dpy, win_info, colors)
  509.      Display *dpy;
  510.      XWindowAttributes *win_info;
  511.      XColor **colors;
  512. {
  513.     int i, ncolors;
  514.  
  515.     if (!win_info->colormap)
  516.     return(0);
  517.  
  518.     if (win_info->visual->class == TrueColor ||
  519.     win_info->visual->class == DirectColor)
  520.     return(0);    /* XXX punt for now */
  521.  
  522.     ncolors = win_info->visual->map_entries;
  523.     if (!(*colors = (XColor *) malloc (sizeof(XColor) * ncolors)))
  524.       fprintf (stderr, "xsnap:  out of memory attempting to allocate colors\n");
  525.  
  526.     for (i=0; i<ncolors; i++)
  527.       (*colors)[i].pixel = i;
  528.  
  529.     XQueryColors(dpy, win_info->colormap, *colors, ncolors);
  530.     
  531.     return(ncolors);
  532. }
  533.  
  534. /*
  535.  * Determine the pixmap size.
  536.  */
  537.  
  538. int Image_Size(image, format)
  539.      XImage *image;
  540.      int format;
  541. {
  542.     if (format != ZPixmap)
  543.       return(image->bytes_per_line * image->height * image->depth);
  544.  
  545.     return(image->bytes_per_line * image->height);
  546. }
  547.  
  548. _swapshort (bp, n)
  549.     register char *bp;
  550.     register unsigned n;
  551. {
  552.     register char c;
  553.     register char *ep = bp + n;
  554.  
  555.     while (bp < ep) {
  556.     c = *bp;
  557.     *bp = *(bp + 1);
  558.     bp++;
  559.     *bp++ = c;
  560.     }
  561. }
  562.  
  563. _swaplong (bp, n)
  564.     register char *bp;
  565.     register unsigned n;
  566. {
  567.     register char c;
  568.     register char *ep = bp + n;
  569.     register char *sp;
  570.  
  571.     while (bp < ep) {
  572.     sp = bp + 3;
  573.     c = *sp;
  574.     *sp = *bp;
  575.     *bp++ = c;
  576.     sp = bp + 1;
  577.     c = *sp;
  578.     *sp = *bp;
  579.     *bp++ = c;
  580.     bp += 2;
  581.     }
  582. }
  583.  
  584. #ifdef ATK
  585. write_atk_bytes (file, curbyte, curcount)
  586.      FILE *file;
  587.      unsigned char curbyte;
  588.      unsigned int curcount;
  589. {     
  590.     /* codes for data stream */
  591. #define WHITEZERO       'f'
  592. #define WHITETWENTY     'z'
  593. #define BLACKZERO       'F'
  594. #define BLACKTWENTY     'Z'
  595. #define OTHERZERO       0x1F
  596.  
  597. #define WHITEBYTE       0x00
  598. #define BLACKBYTE       0xFF
  599.  
  600.   /* WriteRow table for conversion of a byte value to two character hex representation */
  601.  
  602.   static unsigned char hex[16] = {
  603.     '0', '1', '2', '3', '4', '5', '6', '7',
  604.     '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
  605.     };
  606.   switch (curbyte)
  607.     {
  608.     case WHITEBYTE:
  609.       while (curcount > 20) 
  610.     fputc(WHITETWENTY, file),
  611.       curcount -= 20;
  612.       fputc(WHITEZERO + curcount, file);
  613.       break;
  614.     case BLACKBYTE:
  615.       while (curcount > 20) 
  616.     fputc(BLACKTWENTY, file),
  617.       curcount -= 20;
  618.       fputc(BLACKZERO + curcount, file);
  619.       break;
  620.     default:
  621.       while (curcount > 16)
  622.     fputc(OTHERZERO+16, file),
  623.       fputc(hex[curbyte / 16], file),
  624.       fputc(hex[curbyte & 15], file),
  625.       curcount -= 16;
  626.       if (curcount > 1)
  627.     fputc(OTHERZERO+curcount, file);
  628.       else ;    /* the byte written will represent a single instance */
  629.       fputc(hex[curbyte / 16], file);
  630.       fputc(hex[curbyte & 15], file);
  631.     }
  632. }
  633.  
  634.  
  635. process_atk_byte (pcurcount, pcurbyte, file, newbyte, eolflag)
  636. int *pcurcount;
  637. unsigned char *pcurbyte;
  638. FILE *file;
  639. unsigned char newbyte;
  640. int eolflag;
  641. {
  642.     int curcount = *pcurcount;
  643.     unsigned char curbyte = *pcurbyte;
  644.  
  645.     if (*pcurcount < 1)
  646.       {
  647.     *pcurbyte = newbyte;
  648.     *pcurcount = 1;
  649.       }
  650.     else if (newbyte == *pcurbyte)
  651.       {
  652.     *pcurcount = *pcurcount + 1;
  653.       }
  654.     else
  655.       {
  656.     write_atk_bytes (file, *pcurbyte, *pcurcount);
  657.     *pcurcount = 1;
  658.     *pcurbyte = newbyte;
  659.       }
  660.  
  661.     if (eolflag)
  662.       {
  663.     write_atk_bytes (file, *pcurbyte, *pcurcount);
  664.     fprintf (file, " |\n");
  665.     *pcurcount = 0;
  666.     *pcurbyte = 0;
  667.       }
  668. }
  669.  
  670. save_as_atk_file (display, screen, win_info, pixmap, width, height, depth)
  671.      Display *display;
  672.      int screen;
  673.      XWindowAttributes *win_info;
  674.      Pixmap pixmap;
  675.      unsigned int width, height, depth;
  676. {
  677.     XColor *colors;
  678.     int ncolors, i, *color_translate, crunch_to_bw;
  679.     XImage *image;
  680.     FILE *output;
  681.     unsigned char curbyte, newbyte;
  682.     int curcount, gather, line, col;
  683.  
  684.     image = XGetImage (display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap);
  685.  
  686.     if (!image) {
  687.     fprintf (stderr, "xsnap:  unable to get image at %dx%d+%d+%d\n",
  688.          width, height, 0, 0);
  689.     exit (1);
  690.     }
  691.  
  692.     /*
  693.      * Find the output file
  694.      */
  695.     if (output_file_name != NULL)
  696.       output = fopen (output_file_name, "w+");
  697.     if (output_file_name == NULL || output == NULL)
  698.       output = (stdout);
  699.  
  700.     /*
  701.      * Set crunch-to-black-and-white flag
  702.      */
  703.     if (crunch_to_bw = (image->depth > 1))
  704.     {
  705.     ncolors = Get_XColors(display, win_info, &colors);
  706.     color_translate = (int *) malloc (sizeof(int) * ncolors);
  707.     for (i = 0;  i < ncolors;  i += 1)
  708.         color_translate[colors[i].pixel] = ((.30 * colors[i].red + .59 * colors[i].green + .11 * colors[i].blue) > 0x8000) ? 0 : 1;
  709.     }
  710.  
  711. #define CRUNCHPIXEL(pix)  ((crunch_to_bw)?(color_translate[(pix)]):(pix))
  712. #define DEFAULTSCALE (1<<16)
  713. #define RASTERVERSION 2
  714.  
  715.     fprintf(output, "\\begindata{raster,%d}\n", 1);
  716.     fprintf(output, "%ld %ld %ld %ld ", RASTERVERSION, 
  717.          0, DEFAULTSCALE, DEFAULTSCALE);
  718.     fprintf(output, "%ld %ld %ld %ld\n",
  719.          0, 0, width, height);      /* subraster */
  720.     fprintf(output, "bits %ld %ld %ld\n", 1, width, height);
  721.  
  722.     for (line = 0;  line < height;  line += 1)
  723.     {
  724.     gather = 0;
  725.     newbyte = 0;
  726.     curbyte = 0;
  727.     curcount = 0;
  728.     col = 0;
  729.     while (col < width)
  730.     {
  731.         if (gather > 7)
  732.         {
  733.         process_atk_byte (&curcount, &curbyte, output, newbyte, FALSE);
  734.         gather = 0;
  735.         newbyte = 0;
  736.         }
  737.         newbyte = (newbyte << 1) | CRUNCHPIXEL(XGetPixel(image, col, line));
  738.         gather += 1;
  739.         col += 1;
  740.     }
  741.  
  742.     if (gather > 0)
  743.     {
  744.         newbyte = (newbyte << (8 - gather));
  745.         process_atk_byte (&curcount, &curbyte, output, newbyte, TRUE);
  746.     }
  747.     }
  748.  
  749.     fprintf(output, "\\enddata{raster, %d}\n", 1);
  750.  
  751.     if (output != stdout)
  752.     fclose (output);
  753. }
  754. #endif
  755.  
  756. #include "X11/XWDFile.h"
  757.  
  758. save_as_xwd_file (display, screen, win_info, pixmap, width, height, depth)
  759.      Display *display;
  760.      int screen;
  761.      XWindowAttributes *win_info;
  762.      Pixmap pixmap;
  763.      unsigned int width, height, depth;
  764. {
  765.     unsigned long swaptest = 1;
  766.     XColor *colors;
  767.     unsigned buffer_size;
  768.     int win_name_size;
  769.     int header_size;
  770.     int ncolors, i;
  771.     char *win_name;
  772.     XImage *image;
  773.     int absx, absy, x, y;
  774.     int dwidth, dheight;
  775.     int bw;
  776.     XWDFileHeader header;
  777.     FILE *output;
  778.  
  779.     image = XGetImage (display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap);
  780.  
  781.     if (!image) {
  782.     fprintf (stderr, "xsnap:  unable to get image at %dx%d+%d+%d\n",
  783.          width, height, 0, 0);
  784.     exit (1);
  785.     }
  786.  
  787.     /*
  788.      * Find the output file
  789.      */
  790.     if (output_file_name != NULL)
  791.       output = fopen (output_file_name, "w+");
  792.     if (output_file_name == NULL || output == NULL)
  793.       output = (stdout);
  794.  
  795.     /*
  796.      * Determine the pixmap size.
  797.      */
  798.     buffer_size = Image_Size(image, ZPixmap);
  799.  
  800.     ncolors = Get_XColors(display, win_info, &colors);
  801.  
  802.     /*
  803.      * Calculate header size.
  804.      */
  805.     header_size = sizeof(header);
  806.  
  807.     /*
  808.      * Write out header information.
  809.      */
  810.     header.header_size = (xwdval) header_size;
  811.     header.file_version = (xwdval) XWD_FILE_VERSION;
  812.     header.pixmap_format = (xwdval) ZPixmap;
  813.     header.pixmap_depth = (xwdval) image->depth;
  814.     header.pixmap_width = (xwdval) image->width;
  815.     header.pixmap_height = (xwdval) image->height;
  816.     header.xoffset = (xwdval) image->xoffset;
  817.     header.byte_order = (xwdval) image->byte_order;
  818.     header.bitmap_unit = (xwdval) image->bitmap_unit;
  819.     header.bitmap_bit_order = (xwdval) image->bitmap_bit_order;
  820.     header.bitmap_pad = (xwdval) image->bitmap_pad;
  821.     header.bits_per_pixel = (xwdval) image->bits_per_pixel;
  822.     header.bytes_per_line = (xwdval) image->bytes_per_line;
  823.     header.visual_class = (xwdval) win_info->visual->class;
  824.     header.red_mask = (xwdval) win_info->visual->red_mask;
  825.     header.green_mask = (xwdval) win_info->visual->green_mask;
  826.     header.blue_mask = (xwdval) win_info->visual->blue_mask;
  827.     header.bits_per_rgb = (xwdval) win_info->visual->bits_per_rgb;
  828.     header.colormap_entries = (xwdval) win_info->visual->map_entries;
  829.     header.ncolors = ncolors;
  830.     header.window_width = (xwdval) win_info->width;
  831.     header.window_height = (xwdval) win_info->height;
  832.     header.window_x = 0;
  833.     header.window_y = 0;
  834.     header.window_bdrwidth = (xwdval) win_info->border_width;
  835.  
  836.     if (*(char *) &swaptest) {
  837.       _swaplong((char *) &header, sizeof(header));
  838.       for (i = 0; i < ncolors; i++) {
  839.     _swaplong((char *) &colors[i].pixel, sizeof(long));
  840.     _swapshort((char *) &colors[i].red, 3 * sizeof(short));
  841.       }
  842.     }
  843.  
  844.     (void) fwrite((char *)&header, sizeof(header), 1, output);
  845.  
  846.     /*
  847.      * Write out the color maps, if any
  848.      */
  849.     (void) fwrite((char *) colors, sizeof(XColor), ncolors, output);
  850.  
  851.     /*
  852.      *    This copying of the bit stream (data) to a file is to be replaced
  853.      *  by an Xlib call which hasn't been written yet.  It is not clear
  854.      *  what other functions of xwd will be taken over by this (as yet)
  855.      *  non-existant X function.
  856.      */
  857.     (void) fwrite(image->data, (int) buffer_size, 1, output);
  858.  
  859.     /*
  860.      * close the file
  861.      */
  862.     if (output != (stdout))
  863.       fclose (output);
  864.  
  865.     /*
  866.      * free the color buffer.
  867.      */
  868.     if(ncolors > 0) free(colors);
  869.  
  870.     /*
  871.      * Free image
  872.      */
  873.     XDestroyImage(image);
  874. }
  875.  
  876. #ifdef XPM
  877. #include "xpm.h"
  878.  
  879. save_as_xpm_file (display, screen, win_info, pixmap, width, height, depth)
  880.      Display *display;
  881.      int screen;
  882.      XWindowAttributes *win_info;
  883.      Pixmap pixmap;
  884.      unsigned int width, height, depth;
  885. {
  886.     XWritePixmapFile(display, win_info->colormap, output_file_name, 
  887.              pixmap, width, height, NULL, 1, NULL);  
  888. }
  889. #endif
  890.  
  891. save_in_cut_buffer (display, screen, pixmap, width, height, depth)
  892.      Display *display;
  893.      int screen;
  894.      Pixmap pixmap;
  895.      unsigned int width, height, depth;
  896. {
  897. }
  898.  
  899. exitXsnap(the_display, snapshot, snap_pixmap, copy_gc)
  900.      Display *the_display;
  901.      Window snapshot;
  902.      Pixmap snap_pixmap;
  903.      GC copy_gc;
  904. {
  905.   if (snapshot != 0)
  906.     XDestroyWindow(the_display, snapshot);
  907.   XFreePixmap(the_display, snap_pixmap);
  908.   XFreeGC(the_display, copy_gc);
  909.   XCloseDisplay(the_display);
  910.   exit(0);
  911. }
  912.  
  913. main(argc, argv)
  914. int argc;
  915. char **argv;
  916. {
  917.     Display *the_display;
  918.     int the_screen;
  919.     XWMHints wmhints;
  920.     XEvent an_event;
  921.     GC copy_gc;
  922.     unsigned long copy_gc_valuemask;
  923.     XGCValues copy_gc_values;
  924.     long wmhints_mask;
  925.     XSizeHints wm_size_hints;
  926.     int x_return, y_return;           /* for XParseGeometry */
  927.     int width_return, height_return;  /* ditto              */
  928.     int geom_mask;                    /* bitmask for XParseGeometry fields */
  929.     unsigned long border_color_pixel; /* pixel for border color */
  930.     XColor color;
  931.     Colormap cmap;
  932.     Window window_to_snap;            /* always root window, now */
  933.     Window snapshot;
  934.     Cursor snap_cursor;
  935.     Pixmap  snap_pixmap;
  936.     int reg_x, reg_y;
  937.     int icon_x, icon_y;
  938.     int snap_x, snap_y;
  939.     unsigned int snap_width, snap_height;
  940.     unsigned int reg_width, reg_height, reg_depth;
  941.     int done;
  942.     char buffer [4];                     /* key press buffer for XLookupString  */
  943.     int string_length;                       /* length of returned string */
  944.     XWindowAttributes window_attributes;
  945.  
  946.     process_args(argc, argv);
  947.     XSetErrorHandler(my_X_error_handler);
  948.     if ((the_display = XOpenDisplay(display_string)) == NULL)
  949.       {
  950.         
  951.         fprintf(stderr, "Cannot open display:    %s\n", 
  952.             XDisplayName(display_string));
  953.         exit(1);
  954.       }
  955.     XSetErrorHandler(my_X_error_handler);
  956.     the_screen = DefaultScreen(the_display);
  957.     window_to_snap = XRootWindow(the_display, the_screen);
  958.  
  959.     /* make copy GC */
  960.  
  961.     copy_gc_valuemask = GCSubwindowMode;
  962.     copy_gc_values.subwindow_mode = IncludeInferiors;
  963.     copy_gc = XCreateGC(the_display, window_to_snap, copy_gc_valuemask, ©_gc_values);
  964.  
  965.     if (grab_server)
  966.     {
  967.         XGrabServer(the_display);
  968.         XSync(the_display, 0);
  969.     }
  970.  
  971.     if (region_geom_string)
  972.     {
  973.         geom_mask = XParseGeometry(region_geom_string, ®_x, ®_y,
  974.             ®_width, ®_height);
  975.         if ((geom_mask & XValue) && (geom_mask & YValue) &&
  976.             (geom_mask & WidthValue) && (geom_mask & HeightValue))
  977.         /* must specify complete geometry for region */
  978.         {
  979.             if (geom_mask & XNegative)
  980.                 reg_x += DisplayWidth(the_display, the_screen) - reg_width;
  981.             if (geom_mask & YNegative)
  982.                 reg_y += DisplayHeight(the_display, the_screen) - reg_height;
  983.             snap_pixmap = get_pixmap_region(the_display, the_screen, 
  984.                 window_to_snap, copy_gc,
  985.                 ®_x, ®_y, ®_width, 
  986.                 ®_height, ®_depth, FALSE);
  987.         }
  988.         else {
  989.             if (grab_server) {
  990.             XUngrabServer(the_display);
  991.             XSync(the_display, 0);
  992.             }
  993.             usage();
  994.         }
  995.     }
  996.     else 
  997.         snap_pixmap = get_pixmap_region(the_display, the_screen,
  998.                         window_to_snap, copy_gc,
  999.                         ®_x, ®_y,
  1000.                         ®_width, ®_height,
  1001.                         ®_depth, TRUE);
  1002.  
  1003.     /* ungrab the server */
  1004.  
  1005.     if (grab_server) XUngrabServer(the_display);
  1006.  
  1007.     if (display_in_window)
  1008.       {
  1009.         /* process border color */
  1010.  
  1011.         cmap = DefaultColormap(the_display, the_screen);
  1012.         if ((color_name) && (XParseColor(the_display, cmap, color_name, &color)) &&
  1013.         (XAllocColor(the_display, cmap, &color)))
  1014.           border_color_pixel = color.pixel;
  1015.         else
  1016.           border_color_pixel = WhitePixel(the_display, the_screen);
  1017.  
  1018.  
  1019.  
  1020.  
  1021.  
  1022.         /*
  1023.          * get location of our window(from the window_geom_string),
  1024.          * and set up the size hints structure.
  1025.          */     
  1026.         wm_size_hints.flags = 0;
  1027.         width_return = reg_width;
  1028.         height_return = reg_height;
  1029.         wm_size_hints.x = 0;
  1030.         wm_size_hints.y = 0;
  1031.         wm_size_hints.width = reg_width;
  1032.         wm_size_hints.height = reg_height;
  1033.  
  1034.         if (window_geom_string)
  1035.           {
  1036.         geom_mask = XParseGeometry(window_geom_string, &x_return, 
  1037.                        &y_return, &width_return, 
  1038.                        &height_return);
  1039.         if (geom_mask & XValue)
  1040.           {
  1041.             if (geom_mask & XNegative)
  1042.               wm_size_hints.x = DisplayWidth(the_display, 
  1043.                              the_screen)
  1044.             - width_return + x_return - 
  1045.               (border_width * 2);
  1046.             else
  1047.               wm_size_hints.x = x_return;
  1048.           }
  1049.         if (geom_mask & YValue)
  1050.           {
  1051.             if (geom_mask & YNegative)
  1052.               wm_size_hints.y =  
  1053.             DisplayHeight(the_display, the_screen)
  1054.               - height_return + y_return  - 
  1055.                 (border_width * 2);
  1056.  
  1057.             else
  1058.               wm_size_hints.y = y_return;
  1059.           }
  1060.  
  1061.           }
  1062.  
  1063.         if ((geom_mask & XValue) || (geom_mask & YValue))
  1064.           wm_size_hints.flags |= USPosition;
  1065.  
  1066.         if ((geom_mask & WidthValue) || (geom_mask & HeightValue))
  1067.           wm_size_hints.flags |= USSize;
  1068.         wm_size_hints.width = width_return;
  1069.         wm_size_hints.height = height_return;
  1070.         
  1071.  
  1072.         snapshot = XCreateSimpleWindow(the_display, 
  1073.                        XRootWindow(the_display, the_screen), 
  1074.                        wm_size_hints.x, wm_size_hints.y,
  1075.                        wm_size_hints.width, 
  1076.                        wm_size_hints.height, border_width,
  1077.                        border_color_pixel,
  1078.                        BlackPixel(the_display, the_screen));
  1079.  
  1080.         if (window_geom_string)
  1081.           XSetNormalHints(the_display, snapshot, &wm_size_hints);
  1082.         XStoreName(the_display, snapshot, app_name);
  1083.         wmhints_mask = 0;
  1084.         if (start_iconic)
  1085.           {
  1086.         wmhints_mask |= StateHint;
  1087.         wmhints.initial_state = IconicState;
  1088.           }
  1089.         x_return = y_return = 0;
  1090.  
  1091.         /* Icon geometry is sorta broken, since we don't supply an icon, and 
  1092.          * there isn't any way I know of to get the geometry  of the icon that
  1093.          * the window manager will provide.   So, we'll pretend that our icon 
  1094.          * is 32x32 (ugh).
  1095.          */
  1096.  
  1097.         if (icon_geom_string)
  1098.           {
  1099.         geom_mask = XParseGeometry(icon_geom_string, &x_return, 
  1100.                        &y_return, &width_return, 
  1101.                        &height_return);
  1102.         if (geom_mask & XValue)
  1103.           {
  1104.             if (geom_mask & XNegative)
  1105.               wmhints.icon_x = DisplayWidth(the_display, 
  1106.                             the_screen)
  1107.             - 32 + x_return - (border_width * 2);
  1108.             else
  1109.               wmhints.icon_x = x_return;
  1110.           }
  1111.         if (geom_mask & YValue)
  1112.           {
  1113.             if (geom_mask & YNegative)
  1114.               wmhints.icon_y =  DisplayHeight(the_display, 
  1115.                               the_screen)
  1116.             - 32 + y_return  - (border_width * 2);
  1117.  
  1118.             else
  1119.               wmhints.icon_y = y_return;
  1120.           }
  1121.         wmhints_mask |= IconPositionHint;
  1122.           }
  1123.  
  1124.  
  1125.         if (wmhints_mask)
  1126.           {
  1127.         wmhints.flags = wmhints_mask;
  1128.         XSetWMHints(the_display, snapshot, &wmhints);
  1129.           }
  1130.  
  1131.         /* solicit expose events */
  1132.  
  1133.         XSelectInput(the_display, snapshot, ExposureMask | KeyPressMask);
  1134.  
  1135.         /* give it a different cursor */
  1136.  
  1137.         snap_cursor = XCreateFontCursor(the_display, XC_gumby);
  1138.  
  1139.         XDefineCursor(the_display, snapshot, snap_cursor);
  1140.  
  1141.         /* set the background of the window to be the pixmap */
  1142.  
  1143.         XSetWindowBackgroundPixmap (the_display, snapshot, snap_pixmap);
  1144.  
  1145.         /* map it */
  1146.  
  1147.         XMapRaised(the_display, snapshot);
  1148.         XFlush (the_display);
  1149.     }
  1150.  
  1151.     if (xwd_output)
  1152.     {
  1153.         XGetWindowAttributes (the_display, window_to_snap,
  1154.                   &window_attributes);
  1155.         save_as_xwd_file (the_display, the_screen, &window_attributes, snap_pixmap, reg_width, reg_height, reg_depth);
  1156.     }
  1157.  
  1158.     if (atk_output)
  1159.       {
  1160. #ifdef ATK
  1161.         XGetWindowAttributes (the_display, window_to_snap,
  1162.                   &window_attributes);
  1163.         save_as_atk_file (the_display, the_screen, &window_attributes, snap_pixmap, reg_width, reg_height, reg_depth);
  1164. #else
  1165.         printf("This version of xsnap has not be compiled with the atk feature,\n");
  1166.         printf("recompile with ATK defined.\n");
  1167. #endif
  1168.       }
  1169.  
  1170.     if (xpm_output)
  1171.       {
  1172. #ifdef XPM
  1173.         XGetWindowAttributes (the_display, window_to_snap,
  1174.                   &window_attributes);
  1175.         save_as_xpm_file (the_display, the_screen, &window_attributes, snap_pixmap, reg_width, reg_height, reg_depth);
  1176. #else
  1177.         printf("This version of xsnap has not be compiled with the xpm feature,\n");
  1178.         printf("recompile with XPM defined.\n");
  1179. #endif
  1180.       }
  1181.  
  1182.     if (cut_buffer)
  1183.       save_in_cut_buffer (the_display, the_screen, snap_pixmap, reg_width, reg_height, reg_depth);
  1184.  
  1185.     if (!display_in_window)
  1186.       exitXsnap (the_display, NULL, snap_pixmap, copy_gc);
  1187.  
  1188.     /* process events */
  1189.     done = FALSE;
  1190.  
  1191.     while (! done)
  1192.     {
  1193.         XNextEvent(the_display, &an_event);
  1194.         switch (an_event.type)
  1195.         {
  1196.         case MappingNotify:
  1197.             XRefreshKeyboardMapping(&an_event);
  1198.             break;
  1199.         case KeyPress:
  1200.             string_length = XLookupString(&an_event, buffer, 
  1201.                 sizeof(buffer),
  1202.                 NULL, NULL);
  1203.             if ((string_length == 1) && ((buffer[0] == 'q') ||
  1204.                 (buffer[0] == 'Q') ||
  1205.                 (buffer[0] == '\003')))
  1206.               {
  1207.                 /*  clean up  */
  1208.                 exitXsnap(the_display, snapshot, snap_pixmap, copy_gc);
  1209.                 done = TRUE;
  1210.               }
  1211.             break;
  1212.               }
  1213.     }
  1214.  
  1215. }
  1216.